package com.randy.fundation;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

public class XmlUtils {
    public static String attr(NamedNodeMap attributes, String attribute) {
        if (attributes == null || attribute == null) {
            return "";
        }
        Node node = attributes.getNamedItem(attribute);
        if (node != null) {
            return node.getNodeValue();
        }
        return "";
    }

    public static boolean boolAttr(NamedNodeMap attributes, String attribute) {
        return Boolean.parseBoolean(attr(attributes, attribute));
    }

    public static int intAttr(NamedNodeMap attributes, String attribute) {
        return Integer.parseInt(attr(attributes, attribute));
    }

    public static float floatAttr(NamedNodeMap attributes, String attribute) {
        return Float.parseFloat(attr(attributes, attribute));
    }

    public interface ParseCallback {
        void processElement(String elementName, Node element, NamedNodeMap attributes);
    }

    public static void parse(String xmlPath, ParseCallback callback) throws Exception {
        File            file   = new File(xmlPath);
        FileInputStream stream = new FileInputStream(file);

        DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder        docBuilder     = builderFactory.newDocumentBuilder();
        Document               doc            = docBuilder.parse(stream);
        NodeList               rootList       = doc.getElementsByTagName("root");

        Node rootNode = null;
        if (rootList.getLength() == 1) {
            rootNode = rootList.item(0);
        }

        if (rootNode == null) {
            Logger.e("load map failed");
            throw new Exception("can not found 'root' element");
        }

        processElement(rootNode, callback);
    }

    public static void processElement(Node element, ParseCallback callback) {
        NodeList children      = element.getChildNodes();
        int      numberOfChild = children.getLength();
        for (int i = 0; i < numberOfChild; i++) {
            Node node     = children.item(i);
            int  nodeType = node.getNodeType();
            if (nodeType != Node.ELEMENT_NODE) {
                continue;
            }

            callback.processElement(node.getNodeName(), node, node.getAttributes());
        }
    }


    public static String valid(String xmlPath, String xsdPath) {
        String result = "";
        try {
            // parse an XML document into a DOM tree
            DocumentBuilderFactory parserFactory = DocumentBuilderFactory.newInstance();
            parserFactory.setNamespaceAware(true);
            DocumentBuilder parser   = parserFactory.newDocumentBuilder();
            Document        document = parser.parse(new File(xmlPath));

            // create a SchemaFactory capable of understanding WXS schemas
            SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);

            // load a WXS schema, represented by a Schema instance
            javax.xml.transform.Source schemaFile = new StreamSource(new File(xsdPath));
            Schema                           schema     = factory.newSchema(schemaFile);

            // create a Validator instance, which can be used to validate an instance document
            Validator validator = schema.newValidator();

            // validate the DOM tree
            try {
                validator.validate(new DOMSource(document));
            } catch (SAXException e) {
                // instance document is invalid!
            }
        } catch (Exception e) {
            result = e.getMessage();
        }

        return result;
    }
}
